package com.ruoyi.common.utils.json;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author luobo
 * @Date 2021/8/28 10:05
 * @Describetion json对象操作类
 */
@Slf4j
public class JsonUtils {
    private static ObjectMapper mapper = new ObjectMapper();
    private static final ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter();

    static {
        //mapper.setSerializationInclusion(Include.NON_EMPTY); //如果放开此注释，则对象中的值为null时则不会转换
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
        mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        mapper.registerModule(new JavaTimeModule());
    }

    /**
     * @Description 将对象转换为json字符串
     * @version 1.0.0
     * @param node
     * @return
     */
    public static String objToJson(Object node) {
        try {
            return mapper.writeValueAsString(node);
        } catch (JsonProcessingException e) {
            log.error("对象转换json串失败，类：{}", node.getClass().getName(), e);
        }
        return null;
    }

    /**
     * @Description JsonNode对象转换为pojo对象
     * @version 1.0.0
     * @param node
     * @param pojoClass
     * @return
     */
    public static <T> T nodeToPojo(JsonNode node, Class<T> pojoClass) {
        if (node == null) {
            return null;
        }
        try {
            return mapper.treeToValue(node, pojoClass);
        } catch (Exception e) {
            log.error("JsonNode 转换对象失败，类：{}", pojoClass.getName(), e);
        }
        return null;
    }

    /**
     * @Description 将Map对象写成json串
     * @param map
     * @return
     */
    public static String mapToJson(Map<String, Object> map) {
        try {
            return pojoToJson(map, null);
        } catch (Exception e) {
            log.error("Map对象转换json串失败", e);
        }
        return null;
    }

    /**
     * @Description 对象转换为json串
     * @version 1.0.0
     * @param pojo
     * @return
     */
    public static String pojoToJson(Object pojo) {
        try {
            return pojoToJson(pojo, null);
        } catch (Exception e) {
            log.error("POJO对象转换json串失败，类：{}", pojo.getClass().getName(), e);
        }
        return null;
    }

    /**
     * @Description 对象转换为json串
     * @version 1.0.0
     * @param pojo
     * @return
     */
    public static byte[] pojoToJsonByte(Object pojo) {
        try {
            return pojoToJsonByte(pojo, null);
        } catch (Exception e) {
            log.error("POJO对象转换json串失败，类：{}", pojo.getClass().getName(), e);
        }
        return null;
    }

    /**
     * @Description json串转换为对象
     * @version 1.0.0
     * @param json
     * @param pojoClass
     * @param referClass
     * @return
     */
    public static <T, R> T jsonToPojo(String json, Class<T> pojoClass, Class<R> referClass) {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            return mapper.readValue(json, getType(pojoClass, referClass));
        } catch (Exception e) {
            log.error("json串转换POJO对象失败，json串：{}， 类：{}", json, pojoClass.getName(), e);
        }
        return null;
    }

    public static <T> T jsonToPojo(String json, Class<T> pojoClass) {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            return mapper.readValue(json, pojoClass);
        } catch (Exception e) {
            log.error("json串转换POJO对象失败，json串：{}， 类：{}", json, pojoClass.getName(), e);
        }
        return null;
    }

    /**
     * @Description 取集合对象
     * @param json
     * @param name
     * @param type
     * @return
     * @throws Exception
     */
    public static <T> List<T> jsonToList(ObjectNode json, String name, Class<T> type) {
        JsonNode node = json.findPath(name);
        if (node == null) {
            return null;
        }
        List<T> result = null;
        try {
            if (node.isArray()) {
                result = mapper.readValue(node.toString(), getType(ArrayList.class, type));
            } else {
                result = Stream.of(mapper.readValue(node.toString(), type)).map(mapper -> {
                    return (T) mapper;
                }).collect(Collectors.toList());
            }
        } catch (Exception e) {
            log.error("json串转换List对象失败，json串：{}，属性：{}， 类：{}", json.toString(), name, type.getName(), e);
        }
        return result;
    }
    public static <T> List<T> jsonToList(String json, Class<T> type) {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            return mapper.readValue(json, getType(ArrayList.class, type));
        } catch (IOException e) {
            log.error("json串转换List对象失败，json串：{}", json, e);
        }
        return null;
    }

    /**
     * @Description 递归删除所有的fields
     * @version 1.0.0
     * @param node
     * @param fields
     * @return
     */
    public static JsonNode removeRecusive(JsonNode node, List<String> fields) {
        if (node instanceof ObjectNode) {
            Iterator<Map.Entry<String, JsonNode>> it = node.fields();
            while (it.hasNext()) {
                Map.Entry<String, JsonNode> entry = it.next();
                if (fields.contains(entry.getKey())) {
                    it.remove();
                } else {
                    removeRecusive(entry.getValue(), fields);
                }
            }
        } else {
            Iterator<JsonNode> it = node.elements();
            while (it.hasNext()) {
                removeRecusive(it.next(), fields);
            }
        }
        return node;
    }

    private static String pojoToJson(Object obj, SerializationFeature feature) throws Exception {
        String jsonStr = "";
        if (obj == null) {
            return null;
        }
        if (feature == null) {
            jsonStr = mapper.writeValueAsString(obj);
        } else {
            jsonStr = mapper.writer(feature).writeValueAsString(obj);
        }
        return jsonStr;
    }

    private static byte[] pojoToJsonByte(Object obj, SerializationFeature feature) throws Exception {
        byte[] json = null;
        if (obj == null) {
            return null;
        }
        if (feature == null) {
            json = mapper.writeValueAsBytes(obj);
        } else {
            json = mapper.writer(feature).writeValueAsBytes(obj);
        }
        return json;
    }

    private static <R, T> JavaType getType(Class<R> collectionClass, Class<T> elementClasses) {
        return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

    public static String marshal(Object value) throws Exception {
        try {
            return writer.writeValueAsString(value);
        } catch (JsonGenerationException e) {
            throw new Exception(e);
        } catch (JsonMappingException e) {
            throw new Exception(e);
        } catch (IOException e) {
            throw new Exception(e);
        }
    }
}
